Parameters for each preprocessing step

Parameters for sc_trim_barcode

File paths

  • input fastq1: /stornext/General/data/user_managed/grpu_mritchie_1/hickey/SCORE/C084_Hayman_Pasricha/extdata/NN183/scPipe/C084_LC475_mini_bulk_back_up_1:10/C084_LC475_mini_bulk_back_up_1:10.R2.fastq.gz
  • input fastq2: /stornext/General/data/user_managed/grpu_mritchie_1/hickey/SCORE/C084_Hayman_Pasricha/extdata/NN183/scPipe/C084_LC475_mini_bulk_back_up_1:10/C084_LC475_mini_bulk_back_up_1:10.R1.fastq.gz
  • output fastq: /stornext/General/data/user_managed/grpu_mritchie_1/hickey/SCORE/C084_Hayman_Pasricha/extdata/NN183/scPipe/C084_LC475_mini_bulk_back_up_1:10/C084_LC475_mini_bulk_back_up_1:10.combined.fastq.gz

Read structure

assume read1 contains the transcript

  • barcode in read1: NA
  • barcode in read2: start at position 6, length 7
  • UMI in read2: start at position 0, length 6

Read filter

  • remove reads that have N in its barcode or UMI: FALSE
  • remove reads with low quality: TRUE
    • minimum read quality: 20
    • maximum number of base below minimum read quality: 2

Parameters for alignment

  • input fastq: /stornext/General/data/user_managed/grpu_mritchie_1/hickey/SCORE/C084_Hayman_Pasricha/extdata/NN183/scPipe/C084_LC475_mini_bulk_back_up_1:10/C084_LC475_mini_bulk_back_up_1:10.combined.fastq.gz
  • output bam file: /stornext/General/data/user_managed/grpu_mritchie_1/hickey/SCORE/C084_Hayman_Pasricha/extdata/NN183/scPipe/C084_LC475_mini_bulk_back_up_1:10/C084_LC475_mini_bulk_back_up_1:10.combined.subread.bam
  • genome index: /stornext/General/data/user_managed/grpu_mritchie_1/hickey/SCORE/C084_Hayman_Pasricha/extdata/GRCh38.p12/GRCh38_with_ERCC

Parameters for sc_exon_mapping

  • input bam file: /stornext/General/data/user_managed/grpu_mritchie_1/hickey/SCORE/C084_Hayman_Pasricha/extdata/NN183/scPipe/C084_LC475_mini_bulk_back_up_1:10/C084_LC475_mini_bulk_back_up_1:10.combined.subread.bam
  • output bam file: /stornext/General/data/user_managed/grpu_mritchie_1/hickey/SCORE/C084_Hayman_Pasricha/extdata/NN183/scPipe/C084_LC475_mini_bulk_back_up_1:10/C084_LC475_mini_bulk_back_up_1:10.combined.exon.bam
  • transctiptome annotations: /stornext/General/data/user_managed/grpu_mritchie_1/hickey/SCORE/C084_Hayman_Pasricha/extdata/GRCh38.p12/gencode.v28.primary_assembly.annotation.gff3, /stornext/Home/data/allstaff/h/hickey/.local/share/renv/cache/v5/R-4.0/x86_64-pc-linux-gnu/scPipe/1.10.0/af998893c6581660ca447080a261393b/scPipe/extdata/ERCC92_anno.gff3
  • do strand specific mapping: TRUE
  • fix chromosome names: FALSE

Parameters for sc_demultiplex

  • input bam file: /stornext/General/data/user_managed/grpu_mritchie_1/hickey/SCORE/C084_Hayman_Pasricha/extdata/NN183/scPipe/C084_LC475_mini_bulk_back_up_1:10/C084_LC475_mini_bulk_back_up_1:10.combined.exon.bam
  • output folder: /stornext/General/data/user_managed/grpu_mritchie_1/hickey/SCORE/C084_Hayman_Pasricha/extdata/NN183/scPipe/C084_LC475_mini_bulk_back_up_1:10
  • barcode annotation file: /stornext/General/data/user_managed/grpu_mritchie_1/hickey/SCORE/C084_Hayman_Pasricha/extdata/NN183/scPipe/C084_LC475_mini_bulk_back_up_1:10/C084_LC475_mini_bulk_back_up_1:10.barcode_annotation.csv
  • maximum mismatch allowed in barcode: 1

Parameters for sc_gene_counting

  • output folder: /stornext/General/data/user_managed/grpu_mritchie_1/hickey/SCORE/C084_Hayman_Pasricha/extdata/NN183/scPipe/C084_LC475_mini_bulk_back_up_1:10
  • barcode annotation file: /stornext/General/data/user_managed/grpu_mritchie_1/hickey/SCORE/C084_Hayman_Pasricha/extdata/NN183/scPipe/C084_LC475_mini_bulk_back_up_1:10/C084_LC475_mini_bulk_back_up_1:10.barcode_annotation.csv
  • UMI correction: simple correction and merge UMI with distance 1
  • gene filtering: FALSE

Data summary

The organism is “hsapiens_gene_ensembl”, and gene id type is “ensembl_gene_id”.

Overall barcode statistics

if (is.null(params$organism) || is.na(params$organism)) {
  sce = create_sce_by_dir(params$outdir)
} else {
  sce = create_sce_by_dir(params$outdir, organism=params$organism, gene_id_type=params$gene_id_type)
}
overall_stat = demultiplex_info(sce)
datatable(overall_stat, width=800)

Plot barcode match statistics in pie chart:

plot_demultiplex(sce)

Read alignment statistics

ggplotly(plot_mapping(sce, dataname=params$samplename, percentage = FALSE))
ggplotly(plot_mapping(sce, dataname=params$samplename, percentage = TRUE))

Summary and distributions of QC metrics

if (any(colSums(counts(sce)) == 0)) {
  zero_cells = sum(colSums(counts(sce)) == 0)
  sce = sce[, colSums(counts(sce)) > 0]
} else {
  zero_cells = 0
}

Datatable of all QC metrics:

sce = calculate_QC_metrics(sce)
cannot connect to the ensembl database. ERROR:
Error in useMart("ensembl"): could not find function "useMart"
Try to use org.Hs.eg.db.
'select()' returned 1:many mapping between keys and columns
cannot connect to the ensembl database. ERROR:
Error in useMart("ensembl"): could not find function "useMart"
Try to use org.Hs.eg.db.
'select()' returned 1:many mapping between keys and columns
if(!all(colSums(as.data.frame(QC_metrics(sce)))>0)){
  QC_metrics(sce) = QC_metrics(sce)[, colSums(as.data.frame(QC_metrics(sce)))>0]
}
datatable(as.data.frame(QC_metrics(sce)), width=800, options=list(scrollX= TRUE))

Summary of all QC metrics:

datatable(do.call(cbind, lapply(QC_metrics(sce), summary)), width=800, options=list(scrollX= TRUE))

Number of reads mapped to exon before UMI deduplication VS number of genes detected:

ggplotly(ggplot(as.data.frame(QC_metrics(sce)), aes(x=mapped_to_exon, y=number_of_genes))+geom_point(alpha=0.8))
knitr::knit_exit()
LS0tCnRpdGxlOiAic2NQaXBlIHJlcG9ydCBmb3Igc2FtcGxlIGByIHBhcmFtcyRzYW1wbGVuYW1lYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2xsYXBzZWQ6IGZhbHNlCnBhcmFtczoKICBzYW1wbGVuYW1lOiAiQzA4NF9MQzQ3NV9taW5pX2J1bGtfYmFja191cF8xOjEwIgogIGZxMTogIi9zdG9ybmV4dC9HZW5lcmFsL2RhdGEvdXNlcl9tYW5hZ2VkL2dycHVfbXJpdGNoaWVfMS9oaWNrZXkvU0NPUkUvQzA4NF9IYXltYW5fUGFzcmljaGEvZXh0ZGF0YS9OTjE4My9zY1BpcGUvQzA4NF9MQzQ3NV9taW5pX2J1bGtfYmFja191cF8xOjEwL0MwODRfTEM0NzVfbWluaV9idWxrX2JhY2tfdXBfMToxMC5SMi5mYXN0cS5neiIKICBmcTI6ICIvc3Rvcm5leHQvR2VuZXJhbC9kYXRhL3VzZXJfbWFuYWdlZC9ncnB1X21yaXRjaGllXzEvaGlja2V5L1NDT1JFL0MwODRfSGF5bWFuX1Bhc3JpY2hhL2V4dGRhdGEvTk4xODMvc2NQaXBlL0MwODRfTEM0NzVfbWluaV9idWxrX2JhY2tfdXBfMToxMC9DMDg0X0xDNDc1X21pbmlfYnVsa19iYWNrX3VwXzE6MTAuUjEuZmFzdHEuZ3oiCiAgZnFvdXQ6ICIvc3Rvcm5leHQvR2VuZXJhbC9kYXRhL3VzZXJfbWFuYWdlZC9ncnB1X21yaXRjaGllXzEvaGlja2V5L1NDT1JFL0MwODRfSGF5bWFuX1Bhc3JpY2hhL2V4dGRhdGEvTk4xODMvc2NQaXBlL0MwODRfTEM0NzVfbWluaV9idWxrX2JhY2tfdXBfMToxMC9DMDg0X0xDNDc1X21pbmlfYnVsa19iYWNrX3VwXzE6MTAuY29tYmluZWQuZmFzdHEuZ3oiCiAgYmMxX2luZm86ICJOQSIKICBiYzJfaW5mbzogInN0YXJ0IGF0IHBvc2l0aW9uIDYsIGxlbmd0aCA3IgogIHVtaV9pbmZvOiAic3RhcnQgYXQgcG9zaXRpb24gMCwgbGVuZ3RoIDYiCiAgcm1fbjogRkFMU0UKICBybV9sb3c6IFRSVUUKICBtaW5fcTogMjAKICBudW1fYnE6IDIKICBiYW1fYWxpZ246ICIvc3Rvcm5leHQvR2VuZXJhbC9kYXRhL3VzZXJfbWFuYWdlZC9ncnB1X21yaXRjaGllXzEvaGlja2V5L1NDT1JFL0MwODRfSGF5bWFuX1Bhc3JpY2hhL2V4dGRhdGEvTk4xODMvc2NQaXBlL0MwODRfTEM0NzVfbWluaV9idWxrX2JhY2tfdXBfMToxMC9DMDg0X0xDNDc1X21pbmlfYnVsa19iYWNrX3VwXzE6MTAuY29tYmluZWQuc3VicmVhZC5iYW0iCiAgZ19pbmRleDogIi9zdG9ybmV4dC9HZW5lcmFsL2RhdGEvdXNlcl9tYW5hZ2VkL2dycHVfbXJpdGNoaWVfMS9oaWNrZXkvU0NPUkUvQzA4NF9IYXltYW5fUGFzcmljaGEvZXh0ZGF0YS9HUkNoMzgucDEyL0dSQ2gzOF93aXRoX0VSQ0MiCiAgYmFtX21hcDogIi9zdG9ybmV4dC9HZW5lcmFsL2RhdGEvdXNlcl9tYW5hZ2VkL2dycHVfbXJpdGNoaWVfMS9oaWNrZXkvU0NPUkUvQzA4NF9IYXltYW5fUGFzcmljaGEvZXh0ZGF0YS9OTjE4My9zY1BpcGUvQzA4NF9MQzQ3NV9taW5pX2J1bGtfYmFja191cF8xOjEwL0MwODRfTEM0NzVfbWluaV9idWxrX2JhY2tfdXBfMToxMC5jb21iaW5lZC5leG9uLmJhbSIKICBvdXRkaXI6ICIvc3Rvcm5leHQvR2VuZXJhbC9kYXRhL3VzZXJfbWFuYWdlZC9ncnB1X21yaXRjaGllXzEvaGlja2V5L1NDT1JFL0MwODRfSGF5bWFuX1Bhc3JpY2hhL2V4dGRhdGEvTk4xODMvc2NQaXBlL0MwODRfTEM0NzVfbWluaV9idWxrX2JhY2tfdXBfMToxMCIKICBhbm5vX2dmZjogIi9zdG9ybmV4dC9HZW5lcmFsL2RhdGEvdXNlcl9tYW5hZ2VkL2dycHVfbXJpdGNoaWVfMS9oaWNrZXkvU0NPUkUvQzA4NF9IYXltYW5fUGFzcmljaGEvZXh0ZGF0YS9HUkNoMzgucDEyL2dlbmNvZGUudjI4LnByaW1hcnlfYXNzZW1ibHkuYW5ub3RhdGlvbi5nZmYzLCAvc3Rvcm5leHQvSG9tZS9kYXRhL2FsbHN0YWZmL2gvaGlja2V5Ly5sb2NhbC9zaGFyZS9yZW52L2NhY2hlL3Y1L1ItNC4wL3g4Nl82NC1wYy1saW51eC1nbnUvc2NQaXBlLzEuMTAuMC9hZjk5ODg5M2M2NTgxNjYwY2E0NDcwODBhMjYxMzkzYi9zY1BpcGUvZXh0ZGF0YS9FUkNDOTJfYW5uby5nZmYzIgogIHN0bmQ6IFRSVUUKICBmaXhfY2hyOiBGQUxTRQogIGJjX2Fubm86ICIvc3Rvcm5leHQvR2VuZXJhbC9kYXRhL3VzZXJfbWFuYWdlZC9ncnB1X21yaXRjaGllXzEvaGlja2V5L1NDT1JFL0MwODRfSGF5bWFuX1Bhc3JpY2hhL2V4dGRhdGEvTk4xODMvc2NQaXBlL0MwODRfTEM0NzVfbWluaV9idWxrX2JhY2tfdXBfMToxMC9DMDg0X0xDNDc1X21pbmlfYnVsa19iYWNrX3VwXzE6MTAuYmFyY29kZV9hbm5vdGF0aW9uLmNzdiIKICBtYXhfbWlzOiAxCiAgVU1JX2NvcjogInNpbXBsZSBjb3JyZWN0aW9uIGFuZCBtZXJnZSBVTUkgd2l0aCBkaXN0YW5jZSAxIgogIGdlbmVfZmw6IEZBTFNFCiAgb3JnYW5pc206ICJoc2FwaWVuc19nZW5lX2Vuc2VtYmwiCiAgZ2VuZV9pZF90eXBlOiAiZW5zZW1ibF9nZW5lX2lkIgoKLS0tCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShyZWFkcikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShEVCkKbGlicmFyeShzY2F0ZXIpCmxpYnJhcnkoc2NyYW4pCmxpYnJhcnkoc2NQaXBlKQpsaWJyYXJ5KFJ0c25lKQpgYGAKCiMgUGFyYW1ldGVycyBmb3IgZWFjaCBwcmVwcm9jZXNzaW5nIHN0ZXAKCiMjIFBhcmFtZXRlcnMgZm9yIGBzY190cmltX2JhcmNvZGVgCgojIyMgRmlsZSBwYXRocwoKKiBpbnB1dCBmYXN0cTE6IGByIHBhcmFtcyRmcTFgCiogaW5wdXQgZmFzdHEyOiBgciBwYXJhbXMkZnEyYAoqIG91dHB1dCBmYXN0cTogYHIgcGFyYW1zJGZxb3V0YAoKIyMjIFJlYWQgc3RydWN0dXJlCgphc3N1bWUgcmVhZDEgY29udGFpbnMgdGhlIHRyYW5zY3JpcHQKCiogYmFyY29kZSBpbiByZWFkMTogYHIgcGFyYW1zJGJjMV9pbmZvYAoqIGJhcmNvZGUgaW4gcmVhZDI6IGByIHBhcmFtcyRiYzJfaW5mb2AKKiBVTUkgaW4gcmVhZDI6IGByIHBhcmFtcyR1bWlfaW5mb2AKCiMjIyBSZWFkIGZpbHRlcgoKKiByZW1vdmUgcmVhZHMgdGhhdCBoYXZlIGBOYCBpbiBpdHMgYmFyY29kZSBvciBVTUk6IGByIHBhcmFtcyRybV9uYAoqIHJlbW92ZSByZWFkcyB3aXRoIGxvdyBxdWFsaXR5OiBgciBwYXJhbXMkcm1fbG93YApgciBpZiAocGFyYW1zJHJtX2xvdyl7cGFzdGUoIlx0KiBtaW5pbXVtIHJlYWQgcXVhbGl0eToiLCBwYXJhbXMkbWluX3EsICJcbiIsICJcdCogbWF4aW11bSBudW1iZXIgb2YgYmFzZSBiZWxvdyBtaW5pbXVtCnJlYWQgcXVhbGl0eToiLCBwYXJhbXMkbnVtX2JxLCAiXG4iKX1gCgojIyBQYXJhbWV0ZXJzIGZvciBhbGlnbm1lbnQKCiogaW5wdXQgZmFzdHE6IGByIHBhcmFtcyRmcW91dGAKKiBvdXRwdXQgYmFtIGZpbGU6IGByIHBhcmFtcyRiYW1fYWxpZ25gCiogZ2Vub21lIGluZGV4OiBgciBwYXJhbXMkZ19pbmRleGAKCiMjIFBhcmFtZXRlcnMgZm9yIGBzY19leG9uX21hcHBpbmdgCgoqIGlucHV0IGJhbSBmaWxlOiBgciBwYXJhbXMkYmFtX2FsaWduYAoqIG91dHB1dCBiYW0gZmlsZTogYHIgcGFyYW1zJGJhbV9tYXBgCiogdHJhbnNjdGlwdG9tZSBhbm5vdGF0aW9uczogYHIgcGFyYW1zJGFubm9fZ2ZmYAoqIGRvIHN0cmFuZCBzcGVjaWZpYyBtYXBwaW5nOiBgciBwYXJhbXMkc3RuZGAKKiBmaXggY2hyb21vc29tZSBuYW1lczogYHIgcGFyYW1zJGZpeF9jaHJgCgojIyBQYXJhbWV0ZXJzIGZvciBgc2NfZGVtdWx0aXBsZXhgCgoqIGlucHV0IGJhbSBmaWxlOiBgciBwYXJhbXMkYmFtX21hcGAKKiBvdXRwdXQgZm9sZGVyOiBgciBwYXJhbXMkb3V0ZGlyYAoqIGJhcmNvZGUgYW5ub3RhdGlvbiBmaWxlOiBgciBwYXJhbXMkYmNfYW5ub2AKKiBtYXhpbXVtIG1pc21hdGNoIGFsbG93ZWQgaW4gYmFyY29kZTogYHIgcGFyYW1zJG1heF9taXNgCgojIyBQYXJhbWV0ZXJzIGZvciBgc2NfZ2VuZV9jb3VudGluZ2AKCiogb3V0cHV0IGZvbGRlcjogYHIgcGFyYW1zJG91dGRpcmAKKiBiYXJjb2RlIGFubm90YXRpb24gZmlsZTogYHIgcGFyYW1zJGJjX2Fubm9gCiogVU1JIGNvcnJlY3Rpb246IGByIHBhcmFtcyRVTUlfY29yYAoqIGdlbmUgZmlsdGVyaW5nOiBgciBwYXJhbXMkZ2VuZV9mbGAKCiMgRGF0YSBzdW1tYXJ5CgpUaGUgb3JnYW5pc20gaXMgImByIHBhcmFtcyRvcmdhbmlzbWAiLCBhbmQgZ2VuZSBpZCB0eXBlIGlzICJgciBwYXJhbXMkZ2VuZV9pZF90eXBlYCIuCgojIyBPdmVyYWxsIGJhcmNvZGUgc3RhdGlzdGljcwoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmlmIChpcy5udWxsKHBhcmFtcyRvcmdhbmlzbSkgfHwgaXMubmEocGFyYW1zJG9yZ2FuaXNtKSkgewogIHNjZSA9IGNyZWF0ZV9zY2VfYnlfZGlyKHBhcmFtcyRvdXRkaXIpCn0gZWxzZSB7CiAgc2NlID0gY3JlYXRlX3NjZV9ieV9kaXIocGFyYW1zJG91dGRpciwgb3JnYW5pc209cGFyYW1zJG9yZ2FuaXNtLCBnZW5lX2lkX3R5cGU9cGFyYW1zJGdlbmVfaWRfdHlwZSkKfQpvdmVyYWxsX3N0YXQgPSBkZW11bHRpcGxleF9pbmZvKHNjZSkKZGF0YXRhYmxlKG92ZXJhbGxfc3RhdCwgd2lkdGg9ODAwKQpgYGAKClBsb3QgYmFyY29kZSBtYXRjaCBzdGF0aXN0aWNzIGluIHBpZSBjaGFydDoKYGBge3J9CnBsb3RfZGVtdWx0aXBsZXgoc2NlKQpgYGAKCiMjIFJlYWQgYWxpZ25tZW50IHN0YXRpc3RpY3MKCmBgYHtyfQpnZ3Bsb3RseShwbG90X21hcHBpbmcoc2NlLCBkYXRhbmFtZT1wYXJhbXMkc2FtcGxlbmFtZSwgcGVyY2VudGFnZSA9IEZBTFNFKSkKYGBgCgpgYGB7cn0KZ2dwbG90bHkocGxvdF9tYXBwaW5nKHNjZSwgZGF0YW5hbWU9cGFyYW1zJHNhbXBsZW5hbWUsIHBlcmNlbnRhZ2UgPSBUUlVFKSkKYGBgCgojIyBTdW1tYXJ5IGFuZCBkaXN0cmlidXRpb25zIG9mIFFDIG1ldHJpY3MKCmBgYHtyfQppZiAoYW55KGNvbFN1bXMoY291bnRzKHNjZSkpID09IDApKSB7CiAgemVyb19jZWxscyA9IHN1bShjb2xTdW1zKGNvdW50cyhzY2UpKSA9PSAwKQogIHNjZSA9IHNjZVssIGNvbFN1bXMoY291bnRzKHNjZSkpID4gMF0KfSBlbHNlIHsKICB6ZXJvX2NlbGxzID0gMAp9CmBgYAoKYHIgaWYgKHplcm9fY2VsbHMgPiAwKXtwYXN0ZSh6ZXJvX2NlbGxzLCAiY2VsbHMgaGF2ZSB6ZXJvIHJlYWQgY291bnRzLCByZW1vdmUgdGhlbS4iKX1gCgpEYXRhdGFibGUgb2YgYWxsIFFDIG1ldHJpY3M6CmBgYHtyfQpzY2UgPSBjYWxjdWxhdGVfUUNfbWV0cmljcyhzY2UpCmlmKCFhbGwoY29sU3Vtcyhhcy5kYXRhLmZyYW1lKFFDX21ldHJpY3Moc2NlKSkpPjApKXsKICBRQ19tZXRyaWNzKHNjZSkgPSBRQ19tZXRyaWNzKHNjZSlbLCBjb2xTdW1zKGFzLmRhdGEuZnJhbWUoUUNfbWV0cmljcyhzY2UpKSk+MF0KfQpkYXRhdGFibGUoYXMuZGF0YS5mcmFtZShRQ19tZXRyaWNzKHNjZSkpLCB3aWR0aD04MDAsIG9wdGlvbnM9bGlzdChzY3JvbGxYPSBUUlVFKSkKYGBgCgpTdW1tYXJ5IG9mIGFsbCBRQyBtZXRyaWNzOgpgYGB7cn0KZGF0YXRhYmxlKGRvLmNhbGwoY2JpbmQsIGxhcHBseShRQ19tZXRyaWNzKHNjZSksIHN1bW1hcnkpKSwgd2lkdGg9ODAwLCBvcHRpb25zPWxpc3Qoc2Nyb2xsWD0gVFJVRSkpCmBgYAoKTnVtYmVyIG9mIHJlYWRzIG1hcHBlZCB0byBleG9uIGJlZm9yZSBVTUkgZGVkdXBsaWNhdGlvbiBWUyBudW1iZXIgb2YgZ2VuZXMgZGV0ZWN0ZWQ6CmBgYHtyfQpnZ3Bsb3RseShnZ3Bsb3QoYXMuZGF0YS5mcmFtZShRQ19tZXRyaWNzKHNjZSkpLCBhZXMoeD1tYXBwZWRfdG9fZXhvbiwgeT1udW1iZXJfb2ZfZ2VuZXMpKStnZW9tX3BvaW50KGFscGhhPTAuOCkpCmtuaXRyOjprbml0X2V4aXQoKQpgYGAKCiMgUXVhbGl0eSBjb250cm9sCgojIyBEZXRlY3Qgb3V0bGllciBjZWxscwoKQSByb2J1c3RpZmllZCBNYWhhbGFub2JpcyBEaXN0YW5jZSBpcyBjYWxjdWxhdGVkIGZvciBlYWNoIGNlbGwgdGhlbiBvdXRsaWVycyBhcmUgZGV0ZWN0ZWQgYmFzZWQgb24gdGhlIGRpc3RhbmNlLgpIb3dldmVyLCBkdWUgdG8gdGhlIGNvbXBsZXggbmF0dXJlIG9mIHNpbmdsZSBjZWxsIHRyYW5zY3JpcHRvbWVzIGFuZCBwcm90b2NvbCB1c2VkLCBzdWNoIGEgbWV0aG9kIGNhbiBvbmx5IGJlIHVzZWQgdG8KYXNzaXN0IHRoZSBxdWFsaXR5IGNvbnRyb2wgcHJvY2Vzcy4gVmlzdWFsIGluc3BlY3Rpb24gb2YgdGhlIHF1YWxpdHkgY29udHJvbCBtZXRyaWNzIGlzIHN0aWxsIHJlcXVpcmVkLiBCeSBkZWZhdWx0IHdlCnVzZSBgY29tcCA9IDJgIGFuZCB0aGUgYWxnb3JpdGhtIHdpbGwgdHJ5IHRvIHNlcGFyYXRlIHRoZSBxdWFsaXR5IGNvbnRyb2wgbWV0cmljcyBpbnRvIHR3byBnYXVzc2lhbiBjbHVzdGVycy4KClRoZSBudW1iZXIgb2Ygb3V0bGllcnM6CmBgYHtyfQpzY2VfcWMgPSBkZXRlY3Rfb3V0bGllcihzY2UsIHR5cGU9ImxvdyIsIGNvbXAgPSAyKQp0YWJsZShRQ19tZXRyaWNzKHNjZV9xYykkb3V0bGllcnMpCmBgYAoKUGFpcndpc2UgcGxvdCBmb3IgUUMgbWV0cmljcywgY29sb3JlZCBieSBvdXRsaWVyczoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnBsb3RfUUNfcGFpcnMoc2NlX3FjKQpgYGAKCiMjIHBsb3QgaGlnaGVzdCBleHByZXNzaW9uIGdlbmVzCgpSZW1vdmUgbG93IHF1YWxpdHkgY2VsbHMgYW5kIHBsb3QgaGlnaGVzdCBleHByZXNzaW9uIGdlbmVzLgoKYGBge3J9CnNjZV9xYyA9IHJlbW92ZV9vdXRsaWVycyhzY2VfcWMpCnNjZV9xYyA9IGNvbnZlcnRfZ2VuZWlkKHNjZV9xYywgcmV0dXJucz0iZXh0ZXJuYWxfZ2VuZV9uYW1lIikKc2NlX3FjIDwtIGNhbGN1bGF0ZVFDTWV0cmljcyhzY2VfcWMpCnBsb3RIaWdoZXN0RXhwcnMoc2NlX3FjLCBuPTIwKQpgYGAKCiMjIHJlbW92ZSBsb3cgYWJ1bmRhbnQgZ2VuZXMKClBsb3QgdGhlIGF2ZXJhZ2UgY291bnQgZm9yIGVhY2ggZ2VuZXM6CmBgYHtyfQphdmUuY291bnRzIDwtIHJvd01lYW5zKGNvdW50cyhzY2VfcWMpKQpoaXN0KGxvZzEwKGF2ZS5jb3VudHMpLCBicmVha3M9MTAwLCBtYWluPSIiLCBjb2w9ImdyZXk4MCIsCiAgICAgeGxhYj1leHByZXNzaW9uKExvZ1sxMF1+ImF2ZXJhZ2UgY291bnQiKSkKYGBgCgpBcyBhIGxvb3NlIGZpbHRlciB3ZSBrZWVwIGdlbmVzIHRoYXQgYXJlIGV4cHJlc3NlZCBpbiBhdCBsZWFzdCB0d28gY2VsbHMgYW5kIGZvciBjZWxscyB0aGF0IGV4cHJlc3MgdGhhdCBnZW5lLCB0aGUKYXZlcmFnZSBjb3VudCBsYXJnZXIgdGhhbiB0d28uIEhvd2V2ZXIgdGhpcyBpcyBub3QgdGhlIGdvbGQgc3RhbmRhcmQgYW5kIHRoZSBmaWx0ZXIgbWF5IHZhcml5IGRlcGVuZGluZyBvbiB0aGUgZGF0YS4KCmBgYHtyfQprZWVwMSA9IChhcHBseShjb3VudHMoc2NlX3FjKSwgMSwgZnVuY3Rpb24oeCkgbWVhbih4W3g+MF0pKSA+IDEuMSkgICMgYXZlcmFnZSBjb3VudCBsYXJnZXIgdGhhbiAxLjEKa2VlcDIgPSAocm93U3Vtcyhjb3VudHMoc2NlX3FjKT4wKSA+IDUpICAjIGV4cHJlc3NlZCBpbiBhdCBsZWFzdCA1IGNlbGxzCgpzY2VfcWMgPSBzY2VfcWNbKGtlZXAxICYga2VlcDIpLCBdCmRpbShzY2VfcWMpCmBgYAoKV2UgZ290IGByIG5yb3coc2NlX3FjKWAgZ2VuZXMgbGVmdCBhZnRlciByZW1vdmluZyBsb3cgYWJ1bmRhbnQgZ2VuZXMuCgojIERhdGEgbm9ybWFsaXphdGlvbgoKIyMgTm9ybWFsaXphdGlvbiBieSBgc2NyYW5gIGFuZCBgc2NhdGVyYAoKQ29tcHV0ZSB0aGUgbm9ybWFsaXphdGlvbiBzaXplIGZhY3RvcgoKYGBge3J9Cm5jZWxscyA9IG5jb2woc2NlX3FjKQppZiAobmNlbGxzID4gMjAwKSB7CiAgc2NlX3FjIDwtIGNvbXB1dGVTdW1GYWN0b3JzKHNjZV9xYykKfSBlbHNlIHsKICBzY2VfcWMgPC0gY29tcHV0ZVN1bUZhY3RvcnMoc2NlX3FjLCBzaXplcz1hcy5pbnRlZ2VyKGMobmNlbGxzLzcsIG5jZWxscy82LCBuY2VsbHMvNSwgbmNlbGxzLzQsIG5jZWxscy8zKSkpCn0Kc3VtbWFyeShzaXplRmFjdG9ycyhzY2VfcWMpKQpgYGAKCmByIGlmIChtaW4oc2l6ZUZhY3RvcnMoc2NlX3FjKSkgPD0gMCl7cGFzdGUoIldlIGhhdmUgbmVnYXRpdmUgc2l6ZSBmYWN0b3JzIGluIHRoZSBkYXRhLiBUaGV5IGluZGljYXRlIGxvdyBxdWFsaXR5IGNlbGxzCmFuZCB3ZSBoYXZlIHJlbW92ZWQgdGhlbS4gVG8gYXZvaWQgbmVnYXRpdmUgc2l6ZSBmYWN0b3JzLCB0aGUgYmVzdCBzb2x1dGlvbiBpcyB0byBpbmNyZWFzZSB0aGUgc3RyaW5nZW5jeSBvZiB0aGUKZmlsdGVyaW5nLiIpfWAKCmBgYHtyfQppZiAobWluKHNpemVGYWN0b3JzKHNjZV9xYykpIDw9IDApIHsKICBzY2VfcWMgPSBzY2VfcWNbLCBzaXplRmFjdG9ycyhzY2VfcWMpPjBdCn0KYGBgCgpQQ0EgcGxvdCB1c2luZyBnZW5lIGV4cHJlc3Npb25zIGFzIGlucHV0LCBjb2xvcmVkIGJ5IHRoZSBudW1iZXIgb2YgZ2VuZXMuCgpgYGB7cn0KY3BtKHNjZV9xYykgPSBjYWxjdWxhdGVDUE0oc2NlX3FjLCB1c2Vfc2l6ZV9mYWN0b3JzPUZBTFNFKQpwbG90UENBKHNjZV9xYywgcnVuX2FyZ3MgPSBsaXN0KGV4cHJzX3ZhbHVlcz0iY3BtIiksIGNvbG91cl9ieT0idG90YWxfZmVhdHVyZXMiKQpgYGAKCiMjIyBOb3JtYWxpemUgdGhlIGRhdGEgdXNpbmcgc2l6ZSBmYWN0b3IgYW5kIGdldCBoaWdoIHZhcmlhYmxlIGdlbmVzCgpUaGUgaGlnaGx5IHZhcmlhYmxlIGdlbmVzIGFyZSBjaG9zZW4gYmFzZWQgb24gYHRyZW5kVmFyYCBmcm9tIGBzY3JhbmAgd2l0aCBgRkRSID4gMC4wNWAgYW5kIGJpb2xvZ2ljYWwgdmFyaWF0aW9uIGxhcmdlcgp0aGFuIGAwLjVgLiBJZiB0aGUgbnVtYmVyIG9mIGhpZ2hseSB2YXJpYWJsZSBnZW5lcyBpcyBzbWFsbGVyIHRoYW4gMTAwIHdlIHdpbGwgc2VsZWN0IHRoZSB0b3AgMTAwIGdlbmVzIGJ5IGJpb2xvZ2ljYWwKdmFyaWF0aW9uLiBJZiB0aGUgbnVtYmVyIGlzIGxhcmdlciB0aGFuIDUwMCB3ZSB3aWxsIG9ubHkga2VlcCB0b3AgNTAwIGdlbmVzIGJ5IGJpb2xvZ2ljYWwgdmFyaWF0aW9uLgoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnNjZV9xYyA8LSBub3JtYWxpemUoc2NlX3FjKQoKdmFyLmZpdCA8LSB0cmVuZFZhcihzY2VfcWMsIG1ldGhvZD0ibG9lc3MiLCB1c2Uuc3Bpa2VzPUZBTFNFKQp2YXIub3V0IDwtIGRlY29tcG9zZVZhcihzY2VfcWMsIHZhci5maXQpCgppZiAobGVuZ3RoKHdoaWNoKHZhci5vdXQkRkRSIDw9IDAuMDUgJiB2YXIub3V0JGJpbyA+PSAwLjUpKSA8IDUwMCl7CiAgaHZnLm91dCA8LSB2YXIub3V0W29yZGVyKHZhci5vdXQkYmlvLCBkZWNyZWFzaW5nPVRSVUUpWzE6NTAwXSwgXQp9ZWxzZSBpZihsZW5ndGgod2hpY2godmFyLm91dCRGRFIgPD0gMC4wNSAmIHZhci5vdXQkYmlvID49IDAuNSkpID4gMTAwMCl7CiAgaHZnLm91dCA8LSB2YXIub3V0W29yZGVyKHZhci5vdXQkYmlvLCBkZWNyZWFzaW5nPVRSVUUpWzE6MTAwMF0sIF0KfWVsc2V7CiAgaHZnLm91dCA8LSB2YXIub3V0W3doaWNoKHZhci5vdXQkRkRSIDw9IDAuMDUgJiB2YXIub3V0JGJpbyA+PSAwLjUpLCBdCiAgaHZnLm91dCA8LSBodmcub3V0W29yZGVyKGh2Zy5vdXQkYmlvLCBkZWNyZWFzaW5nPVRSVUUpLCBdCn0KCnBsb3QodmFyLm91dCRtZWFuLCB2YXIub3V0JHRvdGFsLCBwY2g9MTYsIGNleD0wLjYsIHhsYWI9Ik1lYW4gbG9nLWV4cHJlc3Npb24iLAogICAgIHlsYWI9IlZhcmlhbmNlIG9mIGxvZy1leHByZXNzaW9uIikKbyA8LSBvcmRlcih2YXIub3V0JG1lYW4pCmxpbmVzKHZhci5vdXQkbWVhbltvXSwgdmFyLm91dCR0ZWNoW29dLCBjb2w9ImRvZGdlcmJsdWUiLCBsd2Q9MikKcG9pbnRzKHZhci5vdXQkbWVhbltyb3duYW1lcyh2YXIub3V0KSAlaW4lIHJvd25hbWVzKGh2Zy5vdXQpXSwgdmFyLm91dCR0b3RhbFtyb3duYW1lcyh2YXIub3V0KSAlaW4lIHJvd25hbWVzKGh2Zy5vdXQpXSwgY29sPSJyZWQiLCBwY2g9MTYpCmBgYAoKIyMgSGVhdG1hcCBvZiB0b3AxMDAgaGlnaCB2YXJpYWJsZSBnZW5lcwoKYGBge3J9CmdlbmVfZXhwID0gZXhwcnMoc2NlX3FjKQoKZ2VuZV9leHAgPSBnZW5lX2V4cFtyb3duYW1lcyhodmcub3V0KVsxOjEwMF0sIF0KCmhjLnJvd3MgPC0gaGNsdXN0KGRpc3QoZ2VuZV9leHApKQpoYy5jb2xzIDwtIGhjbHVzdChkaXN0KHQoZ2VuZV9leHApKSkKCmdlbmVfZXhwID0gZ2VuZV9leHBbaGMucm93cyRvcmRlciwgaGMuY29scyRvcmRlcl0KCm0gPSBsaXN0KAogIGwgPSAxMDAsCiAgciA9IDQwLAogIGIgPSAxMCwKICB0ID0gMTAsCiAgcGFkID0gMAopCgpwbG90X2x5KAogICAgeCA9IGNvbG5hbWVzKGdlbmVfZXhwKSwgeSA9IHJvd25hbWVzKGdlbmVfZXhwKSwKICAgIHogPSBnZW5lX2V4cCwgdHlwZSA9ICJoZWF0bWFwIiklPiUKbGF5b3V0KGF1dG9zaXplID0gRiwgbWFyZ2luID0gbSkKYGBgCgojIERpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiB1c2luZyBoaWdoIHZhcmlhYmxlIGdlbmVzCgojIyBEaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gYnkgUENBCgpgYGB7cn0KcGxvdFBDQShzY2VfcWMsIHJ1bl9hcmdzID0gbGlzdChleHByc192YWx1ZXM9ImxvZ2NvdW50cyIpLCBjb2xvdXJfYnk9InRvdGFsX2ZlYXR1cmVzIikKYGBgCgojIyBEaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gYnkgdC1TTkUKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9My41fQpzZXQuc2VlZCgxMDApCmlmIChhbnkoZHVwbGljYXRlZCh0KGxvZ2NvdW50cyhzY2VfcWMpW3Jvd25hbWVzKGh2Zy5vdXQpLCBdKSkpKSB7CiAgc2NlX3FjID0gc2NlX3FjWywgIWR1cGxpY2F0ZWQodChsb2djb3VudHMoc2NlX3FjKVtyb3duYW1lcyhodmcub3V0KSwgXSkpXQp9Cm91dDUgPC0gcGxvdFRTTkUoc2NlX3FjLCBydW5fYXJncyA9IGxpc3QoZXhwcnNfdmFsdWVzPSJsb2djb3VudHMiLCBwZXJwbGV4aXR5PTEwLGZlYXR1cmVfc2V0PXJvd25hbWVzKGh2Zy5vdXQpKSwgY29sb3VyX2J5PSJ0b3RhbF9mZWF0dXJlcyIpICsgZ2d0aXRsZSgiUGVycGxleGl0eSA9IDEwIikKb3V0MTAgPC0gcGxvdFRTTkUoc2NlX3FjLCBydW5fYXJncyA9IGxpc3QoZXhwcnNfdmFsdWVzPSJsb2djb3VudHMiLCBwZXJwbGV4aXR5PTIwLGZlYXR1cmVfc2V0PXJvd25hbWVzKGh2Zy5vdXQpKSwgY29sb3VyX2J5PSJ0b3RhbF9mZWF0dXJlcyIsCiAgICAgZmVhdHVyZV9zZXQ9cm93bmFtZXMoaHZnLm91dCkpICArIGdndGl0bGUoIlBlcnBsZXhpdHkgPSAyMCIpCm91dDIwIDwtIHBsb3RUU05FKHNjZV9xYywgcnVuX2FyZ3MgPSBsaXN0KGV4cHJzX3ZhbHVlcz0ibG9nY291bnRzIiwgcGVycGxleGl0eT0zMCxmZWF0dXJlX3NldD1yb3duYW1lcyhodmcub3V0KSksIGNvbG91cl9ieT0idG90YWxfZmVhdHVyZXMiLAogICAgIGZlYXR1cmVfc2V0PXJvd25hbWVzKGh2Zy5vdXQpKSAgKyBnZ3RpdGxlKCJQZXJwbGV4aXR5ID0gMzAiKQptdWx0aXBsb3Qob3V0NSwgb3V0MTAsIG91dDIwLCBjb2xzPTMpCmBgYAo=